// @ts-ignore
import axios from 'axios'
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import type { BaseResponse, RequestConfig } from '@/types/request'
// @ts-ignore
import Cookies from 'js-cookie'

class Request {
  private instance: AxiosInstance

  constructor(config: RequestConfig) {
    this.instance = axios.create({
      baseURL: '',
      timeout: 10000,
      ...config,
    })
    this.setupInterceptors()
  }

  // 泛型请求方法
  public async request<T = any>(config: RequestConfig): Promise<BaseResponse<T>> {
    try {
      const response = await this.instance.request<BaseResponse<T>>(config)
      return response.data
    }
    catch (err) {
      return this.handleError(err as AxiosError<BaseResponse>)
    }
  }

  // 拦截器配置
  private setupInterceptors() {
    this.instance.interceptors.request.use(
      // @ts-ignore
      (config: AxiosRequestConfig) => {
        const token = Cookies.get('token')
        if (token) {
          (config.headers as Record<string, any>).Authorization = `Bearer ${token}`
        }
        return config
      },
      (error: AxiosError) => Promise.reject(error),
    )

    this.instance.interceptors.response.use(
      (response: AxiosResponse<BaseResponse>) => {
        if (response.data.code !== 200) {
          return Promise.reject(response.data)
        }
        return response
      },
      (error: AxiosError<BaseResponse>) => {
        this.handleError(error)
        return Promise.reject(error)
      },
    )
  }

  // 统一错误处理
  private handleError(error: AxiosError<BaseResponse>): never {
    const statusMap: Record<number, string> = {
      401: '请重新登录!',
      403: 'Access denied',
      404: '资源未找到!',
      20000: '服务异常请联系管理员!',
    }
    const msg = error.response?.data?.message
      || statusMap[error.response?.status || 500]
      || '位置错误!'
    throw new Error(msg)
  }

  // 快捷方法（带泛型）
  /**
   * 封装 GET 请求方法（带泛型类型安全）
   * @param url 请求路径（必填）
   * @param config 请求配置（可选），包含 headers、params 等 Axios 原生配置
   * @returns Promise<BaseResponse<T>> 包含泛型类型 T 的响应结构
   */
  public get<T = any>(
    url: string,
    config?: RequestConfig,
  ): Promise<BaseResponse<T>> {
    return this.request<T>({ ...config, method: 'GET', url })
  }

  /**
   * 封装 POST 请求方法（带泛型类型安全）
   * @param url 请求路径（必填）
   * @param data 请求体数据（可选）
   * @param config 请求配置（可选），包含 headers、timeout 等扩展配置
   * @returns Promise<BaseResponse<T>> 包含泛型类型 T 的响应结构
   */
  public post<T = any>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<BaseResponse<T>> {
    return this.request<T>({ ...config, method: 'POST', url, data })
  }

  public async upload<T = any>(
    url: string,
    files: File | File[], // 支持单文件或多文件上传
    data?: Record<string, any>, // 其他表单数据
    config?: RequestConfig & { timeout?: number }, // 基础配置  新增timeout类型
    options?: { // 上传专用配置
      fieldName?: string // 文件字段名（默认file）
      multipleField?: boolean // 多文件是否使用多个字段（默认同名追加）
    },
  ): Promise<BaseResponse<T>> {
    const formData = new FormData()// 创建FormData对象
    const fieldName = options?.fieldName || 'file'// 处理文件字段名称
    const isMultipleField = options?.multipleField || false

    // 校验文件参数
    if (!files || (Array.isArray(files) && files.length === 0)) {
      throw new Error('上传文件不能为空')
    }

    const filesArray = Array.isArray(files) ? files : [files]// 处理文件列表（统一转为数组）

    // 添加文件到表单
    filesArray.forEach((file, index) => {
      const finalField = isMultipleField ? `${fieldName}[${index}]` : fieldName
      formData.append(finalField, file, file.name)
    })

    // 添加其他表单数据
    if (data) {
      Object.entries(data).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach(v => formData.append(`${key}[]`, v))
        }
        else if (value instanceof Blob) {
          formData.append(key, value)
        }
        else {
          formData.append(key, String(value))
        }
      })
    }

    // 合并配置（重点处理Content-Type）
    const mergedConfig: RequestConfig = {
      ...config,
      timeout: config?.timeout || 300000, // 默认5分钟超时
      headers: {
        ...config?.headers,
        // 注意：使用FormData时不要设置Content-Type，浏览器会自动添加带boundary的格式
      },
      data: formData,
    }

    // 调用已有的post方法
    // return this.post<T>(url, formData, mergedConfig);
    try {
      const response = await this.post<T>(url, formData, mergedConfig)
      return response
    }
    catch (error) {
      // 统一错误格式
      return {
        code: 500,
        msg: error,
        data: null as T,
      }
    }
  }

  public async uploadExcel<T = any>(
    url: string,
    files: File | File[], // 支持单文件或多文件上传
    data?: Record<string, any>, // 其他表单数据
    config?: RequestConfig & { timeout?: number }, // 基础配置  新增timeout类型
    options?: { // 上传专用配置
      fieldName?: string // 文件字段名（默认file）
      multipleField?: boolean // 多文件是否使用多个字段（默认同名追加）
    },
  ): Promise<BaseResponse<T>> {
    const formData = new FormData()// 创建FormData对象
    const fieldName = options?.fieldName || 'file'// 处理文件字段名称
    const isMultipleField = options?.multipleField || false

    // 校验文件参数
    if (!files || (Array.isArray(files) && files.length === 0)) {
      throw new Error('上传文件不能为空')
    }

    const filesArray = Array.isArray(files) ? files : [files]// 处理文件列表（统一转为数组）

    // 添加文件到表单
    // filesArray.forEach((file, index) => {
    //   const finalField = isMultipleField ? `${fieldName}[${index}]` : fieldName;
    //   formData.append(finalField, file, file.name);
    // });

    filesArray.forEach((file, index) => {
      const fieldNames = ['excel_first', 'excel_second']
      formData.append(fieldNames[index], file, file.name)
    })

    // 添加其他表单数据
    if (data) {
      Object.entries(data).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach(v => formData.append(`${key}[]`, v))
        }
        else if (value instanceof Blob) {
          formData.append(key, value)
        }
        else {
          formData.append(key, String(value))
        }
      })
    }

    // 合并配置（重点处理Content-Type）
    const mergedConfig: RequestConfig = {
      ...config,
      timeout: config?.timeout || 300000, // 默认5分钟超时
      headers: {
        ...config?.headers,
        // 注意：使用FormData时不要设置Content-Type，浏览器会自动添加带boundary的格式
      },
      data: formData,
    }

    // 调用已有的post方法
    // return this.post<T>(url, formData, mergedConfig);
    try {
      const response = await this.post<T>(url, formData, mergedConfig)
      return response
    }
    catch (error) {
      // 统一错误格式
      return {
        code: 20000,
        msg: error,
        data: null as T,
      }
    }
  }
}

export default new Request({})
